﻿using FI.Core.ApplicationContexts;
using FI.Core.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Web;
using System.Web.Mvc;

namespace FI.Security.Mvc
{
    /// <summary>
    /// This custom <see cref="SitemapAuthorizeAttribute"/> is used for authorization.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
    public class SitemapAuthorizeAttribute : AuthorizeAttribute
    {
        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="ActionAuthorizeAttribute"/> is suppress.
        /// </summary>
        /// <value>
        ///   <c>true</c> if suppress; otherwise, <c>false</c>.
        /// </value>
        public bool Suppress { get; set; }

        /// <summary>
        /// Gets or sets the name of error view.
        /// </summary>
        /// <value>
        /// The name of error view.
        /// </value>
        public string ErrorView { get; set; }

        /// <summary>
        /// Gets or sets the name of the error view's master page.
        /// </summary>
        /// <value>
        /// The name of the error view's master page.
        /// </value>
        public string MasterName { get; set; }

        /// <summary>
        /// Gets the authorization context.
        /// </summary>
        public AuthorizationContext AuthorizationContext { get; set; }

        public IList<User> UserList
        {
            get
            {
                if (HttpRuntime.Cache.Get("_sitemap_auth") == null)
                {
                    SiteMapStore store = new SiteMapStore();

                    IList<User> users = store.GetAllUsersWithSiteMap();

                    HttpRuntime.Cache.Insert("_sitemap_auth", users, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(30));

                }

                return HttpRuntime.Cache.Get("_sitemap_auth") as IList<User>;
            }
        }
        /// <summary>
        /// Authorizes the core.
        /// </summary>
        /// <param name="httpContext">The HTTP context.</param>
        /// <returns>A <see cref="bool"/> value indicating whether the current user is authorized.</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            Guard.ArgumentNotNull(httpContext, "httpContext");

            if (this.Suppress)
            {
                return true;
            }

            if (null == this.AuthorizationContext)
            {
                throw new InvalidOperationException("Authorization Context Not Initialize");
            }

            IPrincipal principal = httpContext.User;
            if (!principal.Identity.IsAuthenticated || string.IsNullOrEmpty(ApplicationContext.Current.UserName))
            {
                return false;
            }

            bool isAuthorized = false;


            string area = AuthorizationContext.RouteData.DataTokens["area"] as string;
            string controller = AuthorizationContext.RouteData.GetRequiredString("controller");
            string action = AuthorizationContext.RouteData.GetRequiredString("action");

            var user = this.UserList.Where(n => n.UserName == ApplicationContext.Current.UserName).SingleOrDefault();

            var sitemaps = new List<Sitemap>();
            foreach (var role in user.Roles)
            {
                sitemaps.AddRange(role.Sitemaps);
            }

            isAuthorized = sitemaps.Any(n => n.Area == area && n.Controller == controller && n.Action == action && n.Status==1);
 

            return base.AuthorizeCore(httpContext) && isAuthorized;
        }

  

        /// <summary>
        /// Called when [authorization].
        /// </summary>
        /// <param name="filterContext">The filter context.</param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            Guard.ArgumentNotNull(filterContext, "filterContext");

            AuthorizationContext = filterContext;

      
            base.OnAuthorization(filterContext);
        }
 
    }
}

